/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org

This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

///btDbvtBroadphase implementation by Nathanael Presson

#include "btDbvtBroadphase.h"

//
// Profiling
//

#if DBVT_BP_PROFILE||DBVT_BP_ENABLE_BENCHMARK
#include <stdio.h>
#endif

#if DBVT_BP_PROFILE
struct    ProfileScope
{
    __forceinline ProfileScope(btClock& clock,unsigned long& value) :
    m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds())
    {
    }
    __forceinline ~ProfileScope()
    {
        (*m_value)+=m_clock->getTimeMicroseconds()-m_base;
    }
    btClock*        m_clock;
    unsigned long*    m_value;
    unsigned long    m_base;
};
#define    SPC(_value_)    ProfileScope    spc_scope(m_clock,_value_)
#else
#define    SPC(_value_)
#endif

//
// Helpers
//

//
template <typename T>
static inline void    listappend(T* item,T*& list)
{
    item->links[0]=0;
    item->links[1]=list;
    if(list) list->links[0]=item;
    list=item;
}

//
template <typename T>
static inline void    listremove(T* item,T*& list)
{
    if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1];
    if(item->links[1]) item->links[1]->links[0]=item->links[0];
}

//
template <typename T>
static inline int    listcount(T* root)
{
    int    n=0;
    while(root) { ++n;root=root->links[1]; }
    return(n);
}

//
template <typename T>
static inline void    clear(T& value)
{
    static const struct ZeroDummy : T {} zerodummy;
    value=zerodummy;
}

//
// Colliders
//

/* Tree collider    */
struct    btDbvtTreeCollider : btDbvt::ICollide
{
    btDbvtBroadphase*    pbp;
    btDbvtProxy*        proxy;
    btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {}
    void    Process(const btDbvtNode* na,const btDbvtNode* nb)
    {
        if(na!=nb)
        {
            btDbvtProxy*    pa=(btDbvtProxy*)na->data;
            btDbvtProxy*    pb=(btDbvtProxy*)nb->data;
#if DBVT_BP_SORTPAIRS
            if(pa->m_uniqueId>pb->m_uniqueId)
                btSwap(pa,pb);
#endif
            pbp->m_paircache->addOverlappingPair(pa,pb);
            ++pbp->m_newpairs;
        }
    }
    void    Process(const btDbvtNode* n)
    {
        Process(n,proxy->leaf);
    }
};

//
// btDbvtBroadphase
//

//
btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache)
{
    m_deferedcollide    =    false;
    m_needcleanup        =    true;
    m_releasepaircache    =    (paircache!=0)?false:true;
    m_prediction        =    0;
    m_stageCurrent        =    0;
    m_fixedleft            =    0;
    m_fupdates            =    1;
    m_dupdates            =    0;
    m_cupdates            =    10;
    m_newpairs            =    1;
    m_updates_call        =    0;
    m_updates_done        =    0;
    m_updates_ratio        =    0;
    m_paircache            =    paircache? paircache    : new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
    m_gid                =    0;
    m_pid                =    0;
    m_cid                =    0;
    for(int i=0;i<=STAGECOUNT;++i)
    {
        m_stageRoots[i]=0;
    }
#if DBVT_BP_PROFILE
    clear(m_profiling);
#endif
}

//
btDbvtBroadphase::~btDbvtBroadphase()
{
    if(m_releasepaircache)
    {
        m_paircache->~btOverlappingPairCache();
        btAlignedFree(m_paircache);
    }
}

//
btBroadphaseProxy*                btDbvtBroadphase::createProxy(    const btVector3& aabbMin,
                                                              const btVector3& aabbMax,
                                                              int /*shapeType*/,
                                                              void* userPtr,
                                                              short int collisionFilterGroup,
                                                              short int collisionFilterMask,
                                                              btDispatcher* /*dispatcher*/,
                                                              void* /*multiSapProxy*/)
{
    btDbvtProxy*        proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy(    aabbMin,aabbMax,userPtr,
        collisionFilterGroup,
        collisionFilterMask);

    btDbvtAabbMm aabb = btDbvtVolume::FromMM(aabbMin,aabbMax);

    //bproxy->aabb            =    btDbvtVolume::FromMM(aabbMin,aabbMax);
    proxy->stage        =    m_stageCurrent;
    proxy->m_uniqueId    =    ++m_gid;
    proxy->leaf            =    m_sets[0].insert(aabb,proxy);
    listappend(proxy,m_stageRoots[m_stageCurrent]);
    if(!m_deferedcollide)
    {
        btDbvtTreeCollider    collider(this);
        collider.proxy=proxy;
        m_sets[0].collideTV(m_sets[0].m_root,aabb,collider);
        m_sets[1].collideTV(m_sets[1].m_root,aabb,collider);
    }
    return(proxy);
}

//
void                            btDbvtBroadphase::destroyProxy(    btBroadphaseProxy* absproxy,
                                                               btDispatcher* dispatcher)
{
    btDbvtProxy*    proxy=(btDbvtProxy*)absproxy;
    if(proxy->stage==STAGECOUNT)
        m_sets[1].remove(proxy->leaf);
    else
        m_sets[0].remove(proxy->leaf);
    listremove(proxy,m_stageRoots[proxy->stage]);
    m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher);
    btAlignedFree(proxy);
    m_needcleanup=true;
}

void    btDbvtBroadphase::getAabb(btBroadphaseProxy* absproxy,btVector3& aabbMin, btVector3& aabbMax ) const
{
    btDbvtProxy*                        proxy=(btDbvtProxy*)absproxy;
    aabbMin = proxy->m_aabbMin;
    aabbMax = proxy->m_aabbMax;
}

struct    BroadphaseRayTester : btDbvt::ICollide
{
    btBroadphaseRayCallback& m_rayCallback;
    BroadphaseRayTester(btBroadphaseRayCallback& orgCallback)
        :m_rayCallback(orgCallback)
    {
    }
    void                    Process(const btDbvtNode* leaf)
    {
        btDbvtProxy*    proxy=(btDbvtProxy*)leaf->data;
        m_rayCallback.process(proxy);
    }
};

void    btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax)
{
    BroadphaseRayTester callback(rayCallback);

    m_sets[0].rayTestInternal(    m_sets[0].m_root,
        rayFrom,
        rayTo,
        rayCallback.m_rayDirectionInverse,
        rayCallback.m_signs,
        rayCallback.m_lambda_max,
        aabbMin,
        aabbMax,
        callback);

    m_sets[1].rayTestInternal(    m_sets[1].m_root,
        rayFrom,
        rayTo,
        rayCallback.m_rayDirectionInverse,
        rayCallback.m_signs,
        rayCallback.m_lambda_max,
        aabbMin,
        aabbMax,
        callback);

}


//
void                            btDbvtBroadphase::setAabb(        btBroadphaseProxy* absproxy,
                                                          const btVector3& aabbMin,
                                                          const btVector3& aabbMax,
                                                          btDispatcher* /*dispatcher*/)
{
    btDbvtProxy*                        proxy=(btDbvtProxy*)absproxy;
    ATTRIBUTE_ALIGNED16(btDbvtVolume)    aabb=btDbvtVolume::FromMM(aabbMin,aabbMax);
#if DBVT_BP_PREVENTFALSEUPDATE
    if(NotEqual(aabb,proxy->leaf->volume))
#endif
    {
        bool    docollide=false;
        if(proxy->stage==STAGECOUNT)
        {/* fixed -> dynamic set    */
            m_sets[1].remove(proxy->leaf);
            proxy->leaf=m_sets[0].insert(aabb,proxy);
            docollide=true;
        }
        else
        {/* dynamic set                */
            ++m_updates_call;
            if(Intersect(proxy->leaf->volume,aabb))
            {/* Moving                */

                const btVector3    delta=aabbMin-proxy->m_aabbMin;
                btVector3        velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction);
                if(delta[0]<0) velocity[0]=-velocity[0];
                if(delta[1]<0) velocity[1]=-velocity[1];
                if(delta[2]<0) velocity[2]=-velocity[2];
                if    (
#ifdef DBVT_BP_MARGIN
                    m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN)
#else
                    m_sets[0].update(proxy->leaf,aabb,velocity)
#endif
                    )
                {
                    ++m_updates_done;
                    docollide=true;
                }
            }
            else
            {/* Teleporting            */
                m_sets[0].update(proxy->leaf,aabb);
                ++m_updates_done;
                docollide=true;
            }
        }
        listremove(proxy,m_stageRoots[proxy->stage]);
        proxy->m_aabbMin = aabbMin;
        proxy->m_aabbMax = aabbMax;
        proxy->stage    =    m_stageCurrent;
        listappend(proxy,m_stageRoots[m_stageCurrent]);
        if(docollide)
        {
            m_needcleanup=true;
            if(!m_deferedcollide)
            {
                btDbvtTreeCollider    collider(this);
                m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider);
                m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider);
            }
        }
    }
}

//
void                            btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
{
    collide(dispatcher);
#if DBVT_BP_PROFILE
    if(0==(m_pid%DBVT_BP_PROFILING_RATE))
    {
        printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs());
        unsigned int    total=m_profiling.m_total;
        if(total<=0) total=1;
        printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE);
        printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE);
        printf("cleanup:   %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE);
        printf("total:     %uus\r\n",total/DBVT_BP_PROFILING_RATE);
        const unsigned long    sum=m_profiling.m_ddcollide+
            m_profiling.m_fdcollide+
            m_profiling.m_cleanup;
        printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE);
        printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE));
        clear(m_profiling);
        m_clock.reset();
    }
#endif

    performDeferredRemoval(dispatcher);

}

void btDbvtBroadphase::performDeferredRemoval(btDispatcher* dispatcher)
{

    if (m_paircache->hasDeferredRemoval())
    {

        btBroadphasePairArray&    overlappingPairArray = m_paircache->getOverlappingPairArray();

        //perform a sort, to find duplicates and to sort 'invalid' pairs to the end
        overlappingPairArray.quickSort(btBroadphasePairSortPredicate());

        int invalidPair = 0;


        int i;

        btBroadphasePair previousPair;
        previousPair.m_pProxy0 = 0;
        previousPair.m_pProxy1 = 0;
        previousPair.m_algorithm = 0;


        for (i=0;i<overlappingPairArray.size();i++)
        {

            btBroadphasePair& pair = overlappingPairArray[i];

            bool isDuplicate = (pair == previousPair);

            previousPair = pair;

            bool needsRemoval = false;

            if (!isDuplicate)
            {
                //important to perform AABB check that is consistent with the broadphase
                btDbvtProxy*        pa=(btDbvtProxy*)pair.m_pProxy0;
                btDbvtProxy*        pb=(btDbvtProxy*)pair.m_pProxy1;
                bool hasOverlap = Intersect(pa->leaf->volume,pb->leaf->volume);

                if (hasOverlap)
                {
                    needsRemoval = false;
                } else
                {
                    needsRemoval = true;
                }
            } else
            {
                //remove duplicate
                needsRemoval = true;
                //should have no algorithm
                btAssert(!pair.m_algorithm);
            }

            if (needsRemoval)
            {
                m_paircache->cleanOverlappingPair(pair,dispatcher);

                pair.m_pProxy0 = 0;
                pair.m_pProxy1 = 0;
                invalidPair++;
            }

        }

        //perform a sort, to sort 'invalid' pairs to the end
        overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
        overlappingPairArray.resize(overlappingPairArray.size() - invalidPair);
    }
}

//
void                            btDbvtBroadphase::collide(btDispatcher* dispatcher)
{
    /*printf("---------------------------------------------------------\n");
    printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves);
    printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves);
    printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs());
    {
        int i;
        for (i=0;i<getOverlappingPairCache()->getNumOverlappingPairs();i++)
        {
            printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(),
                getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid());
        }
        printf("\n");
    }
*/



    SPC(m_profiling.m_total);
    /* optimize                */
    m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100);
    if(m_fixedleft)
    {
        const int count=1+(m_sets[1].m_leaves*m_fupdates)/100;
        m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100);
        m_fixedleft=btMax<int>(0,m_fixedleft-count);
    }
    /* dynamic -> fixed set    */
    m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT;
    btDbvtProxy*    current=m_stageRoots[m_stageCurrent];
    if(current)
    {
        btDbvtTreeCollider    collider(this);
        do    {
            btDbvtProxy*    next=current->links[1];
            listremove(current,m_stageRoots[current->stage]);
            listappend(current,m_stageRoots[STAGECOUNT]);
#if DBVT_BP_ACCURATESLEEPING
            m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher);
            collider.proxy=current;
            btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider);
            btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider);
#endif
            m_sets[0].remove(current->leaf);
            ATTRIBUTE_ALIGNED16(btDbvtVolume)    curAabb=btDbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax);
            current->leaf    =    m_sets[1].insert(curAabb,current);
            current->stage    =    STAGECOUNT;
            current            =    next;
        } while(current);
        m_fixedleft=m_sets[1].m_leaves;
        m_needcleanup=true;
    }
    /* collide dynamics        */
    {
        btDbvtTreeCollider    collider(this);
        if(m_deferedcollide)
        {
            SPC(m_profiling.m_fdcollide);
            m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider);
        }
        if(m_deferedcollide)
        {
            SPC(m_profiling.m_ddcollide);
            m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider);
        }
    }
    /* clean up                */
    if(m_needcleanup)
    {
        SPC(m_profiling.m_cleanup);
        btBroadphasePairArray&    pairs=m_paircache->getOverlappingPairArray();
        if(pairs.size()>0)
        {

            int            ni=btMin(pairs.size(),btMax<int>(m_newpairs,(pairs.size()*m_cupdates)/100));
            for(int i=0;i<ni;++i)
            {
                btBroadphasePair&    p=pairs[(m_cid+i)%pairs.size()];
                btDbvtProxy*        pa=(btDbvtProxy*)p.m_pProxy0;
                btDbvtProxy*        pb=(btDbvtProxy*)p.m_pProxy1;
                if(!Intersect(pa->leaf->volume,pb->leaf->volume))
                {
#if DBVT_BP_SORTPAIRS
                    if(pa->m_uniqueId>pb->m_uniqueId)
                        btSwap(pa,pb);
#endif
                    m_paircache->removeOverlappingPair(pa,pb,dispatcher);
                    --ni;--i;
                }
            }
            if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0;
        }
    }
    ++m_pid;
    m_newpairs=1;
    m_needcleanup=false;
    if(m_updates_call>0)
    { m_updates_ratio=m_updates_done/(btScalar)m_updates_call; }
    else
    { m_updates_ratio=0; }
    m_updates_done/=2;
    m_updates_call/=2;
}

//
void                            btDbvtBroadphase::optimize()
{
    m_sets[0].optimizeTopDown();
    m_sets[1].optimizeTopDown();
}

//
btOverlappingPairCache*            btDbvtBroadphase::getOverlappingPairCache()
{
    return(m_paircache);
}

//
const btOverlappingPairCache*    btDbvtBroadphase::getOverlappingPairCache() const
{
    return(m_paircache);
}

//
void                            btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
{

    ATTRIBUTE_ALIGNED16(btDbvtVolume)    bounds;

    if(!m_sets[0].empty())
        if(!m_sets[1].empty())    Merge(    m_sets[0].m_root->volume,
            m_sets[1].m_root->volume,bounds);
        else
            bounds=m_sets[0].m_root->volume;
    else if(!m_sets[1].empty())    bounds=m_sets[1].m_root->volume;
    else
        bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0);
    aabbMin=bounds.Mins();
    aabbMax=bounds.Maxs();
}

void btDbvtBroadphase::resetPool(btDispatcher* dispatcher)
{

    int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves;
    if (!totalObjects)
    {
        //reset internal dynamic tree data structures
        m_sets[0].clear();
        m_sets[1].clear();

        m_deferedcollide    =    false;
        m_needcleanup        =    true;
        m_stageCurrent        =    0;
        m_fixedleft            =    0;
        m_fupdates            =    1;
        m_dupdates            =    0;
        m_cupdates            =    10;
        m_newpairs            =    1;
        m_updates_call        =    0;
        m_updates_done        =    0;
        m_updates_ratio        =    0;

        m_gid                =    0;
        m_pid                =    0;
        m_cid                =    0;
        for(int i=0;i<=STAGECOUNT;++i)
        {
            m_stageRoots[i]=0;
        }
    }
}

//
void                            btDbvtBroadphase::printStats()
{}

//
#if DBVT_BP_ENABLE_BENCHMARK

struct    btBroadphaseBenchmark
{
    struct    Experiment
    {
        const char*            name;
        int                    object_count;
        int                    update_count;
        int                    spawn_count;
        int                    iterations;
        btScalar            speed;
        btScalar            amplitude;
    };
    struct    Object
    {
        btVector3            center;
        btVector3            extents;
        btBroadphaseProxy*    proxy;
        btScalar            time;
        void                update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi)
        {
            time        +=    speed;
            center[0]    =    btCos(time*(btScalar)2.17)*amplitude+
                btSin(time)*amplitude/2;
            center[1]    =    btCos(time*(btScalar)1.38)*amplitude+
                btSin(time)*amplitude;
            center[2]    =    btSin(time*(btScalar)0.777)*amplitude;
            pbi->setAabb(proxy,center-extents,center+extents,0);
        }
    };
    static int        UnsignedRand(int range=RAND_MAX-1)    { return(rand()%(range+1)); }
    static btScalar    UnitRand()                            { return(UnsignedRand(16384)/(btScalar)16384); }
    static void        OutputTime(const char* name,btClock& c,unsigned count=0)
    {
        const unsigned long    us=c.getTimeMicroseconds();
        const unsigned long    ms=(us+500)/1000;
        const btScalar        sec=us/(btScalar)(1000*1000);
        if(count>0)
            printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec);
        else
            printf("%s : %u us (%u ms)\r\n",name,us,ms);
    }
};

void                            btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi)
{
    static const btBroadphaseBenchmark::Experiment        experiments[]=
    {
        {"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100},
        /*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100},
        {"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/
    };
    static const int                                        nexperiments=sizeof(experiments)/sizeof(experiments[0]);
    btAlignedObjectArray<btBroadphaseBenchmark::Object*>    objects;
    btClock                                                    wallclock;
    /* Begin            */
    for(int iexp=0;iexp<nexperiments;++iexp)
    {
        const btBroadphaseBenchmark::Experiment&    experiment=experiments[iexp];
        const int                                    object_count=experiment.object_count;
        const int                                    update_count=(object_count*experiment.update_count)/100;
        const int                                    spawn_count=(object_count*experiment.spawn_count)/100;
        const btScalar                                speed=experiment.speed;
        const btScalar                                amplitude=experiment.amplitude;
        printf("Experiment #%u '%s':\r\n",iexp,experiment.name);
        printf("\tObjects: %u\r\n",object_count);
        printf("\tUpdate: %u\r\n",update_count);
        printf("\tSpawn: %u\r\n",spawn_count);
        printf("\tSpeed: %f\r\n",speed);
        printf("\tAmplitude: %f\r\n",amplitude);
        srand(180673);
        /* Create objects    */
        wallclock.reset();
        objects.reserve(object_count);
        for(int i=0;i<object_count;++i)
        {
            btBroadphaseBenchmark::Object*    po=new btBroadphaseBenchmark::Object();
            po->center[0]=btBroadphaseBenchmark::UnitRand()*50;
            po->center[1]=btBroadphaseBenchmark::UnitRand()*50;
            po->center[2]=btBroadphaseBenchmark::UnitRand()*50;
            po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2;
            po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2;
            po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2;
            po->time=btBroadphaseBenchmark::UnitRand()*2000;
            po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0);
            objects.push_back(po);
        }
        btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock);
        /* First update        */
        wallclock.reset();
        for(int i=0;i<objects.size();++i)
        {
            objects[i]->update(speed,amplitude,pbi);
        }
        btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock);
        /* Updates            */
        wallclock.reset();
        for(int i=0;i<experiment.iterations;++i)
        {
            for(int j=0;j<update_count;++j)
            {
                objects[j]->update(speed,amplitude,pbi);
            }
            pbi->calculateOverlappingPairs(0);
        }
        btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations);
        /* Clean up            */
        wallclock.reset();
        for(int i=0;i<objects.size();++i)
        {
            pbi->destroyProxy(objects[i]->proxy,0);
            delete objects[i];
        }
        objects.resize(0);
        btBroadphaseBenchmark::OutputTime("\tRelease",wallclock);
    }

}
#else
void                            btDbvtBroadphase::benchmark(btBroadphaseInterface*)
{}
#endif

#if DBVT_BP_PROFILE
#undef    SPC
#endif
